﻿using ConsoleHoster.Common.Utilities.IO;
using ConsoleHoster.Model.Suggestions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
using TestUtilities;

namespace ConsoleHoster.UnitTests.ModelTests.SuggestionsTests
{
	[TestClass]
	public class PathSuggestionProviderTests
	{
		private PathSuggestionProvider suggestionProvider;
		private Mock<IFileSystemContentProvider> mockDirectoryContentProvider;

		[TestInitialize]
		public void Initialize()
		{
			this.mockDirectoryContentProvider = new Mock<IFileSystemContentProvider>();
			this.suggestionProvider = new PathSuggestionProvider(this.mockDirectoryContentProvider.Object);
		}

		[TestMethod]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Constructor_ThrowsOnNullDirectoryContentProvider()
		{
			new PathSuggestionProvider(null);
		}

		[TestMethod]
		public void PrepareSuggestions_ThrowsIfDirectoryDoesNotExist()
		{
			const string tmpFolder = "C:\anyFolder";
			this.mockDirectoryContentProvider.Setup(p => p.DirectoryExists(tmpFolder)).Returns(false);

			AssertExtensions.Throws<ArgumentException>(() =>
			{
				this.suggestionProvider.PrepareSuggestions(tmpFolder, "a", false);
			});
			this.mockDirectoryContentProvider.Verify(p => p.DirectoryExists(tmpFolder), Times.Once());

			AssertExtensions.Throws<ArgumentException>(() =>
			{
				this.suggestionProvider.PrepareSuggestions(tmpFolder, "a", true);
			});
			this.mockDirectoryContentProvider.Verify(p => p.DirectoryExists(tmpFolder), Times.Exactly(2));
		}

		[TestMethod]
		public void PrepareSuggestions_RequestsAllItemsThroughDirectoryContentProvider()
		{
			const string tmpFolder = "C:\\windows";
			string tmpPattern = Guid.NewGuid().ToString();

			this.mockDirectoryContentProvider.Setup(p => p.DirectoryExists(tmpFolder)).Returns(true);
			string[] tmpSuggestions = this.suggestionProvider.PrepareSuggestions(tmpFolder, tmpPattern, false);

			this.mockDirectoryContentProvider.Verify(p => p.GetAllItems(tmpFolder, tmpPattern), Times.Once());
		}

		[TestMethod]
		public void PrepareSuggestions_RequestsFoldersThroughDirectoryContentProvider()
		{
			const string tmpFolder = "C:\\windows";
			string[] tmpItems = new[]
				{
					"folder1",
					"folder2"
				};
			string tmpPattern = Guid.NewGuid().ToString();

			this.mockDirectoryContentProvider.Setup(p => p.DirectoryExists(tmpFolder)).Returns(true);
			this.mockDirectoryContentProvider.Setup(p => p.GetFolders(tmpFolder, tmpPattern)).Returns(tmpItems);

			string[] tmpSuggestions = this.suggestionProvider.PrepareSuggestions(tmpFolder, tmpPattern, true);

			AssertExtensions.ArraysEqual<string>(tmpItems, tmpSuggestions);
		}

		[TestMethod]
		public void PrepareSuggestions_ReturnsOnlyFilenames()
		{
			const string tmpFolder = "C:\\windows";
			string[] tmpItems = new[]
				{
					"C:\\file1.txt"
				};
			string tmpPattern = Guid.NewGuid().ToString();

			this.mockDirectoryContentProvider.Setup(p => p.DirectoryExists(tmpFolder)).Returns(true);
			this.mockDirectoryContentProvider.Setup(p => p.GetAllItems(tmpFolder, tmpPattern)).Returns(tmpItems);

			string[] tmpSuggestions = this.suggestionProvider.PrepareSuggestions(tmpFolder, tmpPattern, false);

			AssertExtensions.ArraysEqual<string>(new[] { "file1.txt" }, tmpSuggestions);
		}

		[TestMethod]
		public void GetNextSuggestion_ReturnsNullIfNotConfigured()
		{
			Assert.IsNull(this.suggestionProvider.GetNextSuggestion());
		}

		[TestMethod]
		public void GetNextSuggestion_IncrementsLastSuggestionIndex()
		{
			const string tmpFolder = "C:";
			const string tmpFile1 = "file1.txt";
			const string tmpFile2 = "file2.log";
			string[] tmpItems = new[]
				{
					tmpFile1,
					tmpFile2
				};
			string tmpPattern = "f";

			this.mockDirectoryContentProvider.Setup(p => p.DirectoryExists(tmpFolder)).Returns(true);
			this.mockDirectoryContentProvider.Setup(p => p.GetAllItems(tmpFolder, tmpPattern)).Returns(tmpItems);

			string[] tmpSuggestions = this.suggestionProvider.PrepareSuggestions(tmpFolder, tmpPattern, false);

			Assert.IsNull(this.suggestionProvider.LastSuggestionIndex);
			string tmpActualSuggestion = this.suggestionProvider.GetNextSuggestion();
			Assert.AreEqual(tmpFile1, tmpActualSuggestion);
			Assert.AreEqual(0, this.suggestionProvider.LastSuggestionIndex);

			tmpActualSuggestion = this.suggestionProvider.GetNextSuggestion();
			Assert.AreEqual(1, this.suggestionProvider.LastSuggestionIndex);
			Assert.AreEqual(tmpFile2, tmpActualSuggestion);
		}

		[TestMethod]
		public void GetPreviousSuggestion_ReturnsNullIfNotConfigured()
		{
			Assert.IsNull(this.suggestionProvider.SuggestionBase);
			Assert.IsNull(this.suggestionProvider.GetPreviousSuggestion());
		}

		[TestMethod]
		public void GetPreviousSuggestion_DecrementLastSuggestionIndex()
		{
			const string tmpFolder = "C:";
			const string tmpFile1 = "folder1";
			const string tmpFile2 = "folder2";
			string[] tmpItems = new[]
				{
					tmpFile1,
					tmpFile2
				};
			string tmpPattern = "f";

			this.mockDirectoryContentProvider.Setup(p => p.DirectoryExists(tmpFolder)).Returns(true);
			this.mockDirectoryContentProvider.Setup(p => p.GetFolders(tmpFolder, tmpPattern)).Returns(tmpItems);

			string[] tmpSuggestions = this.suggestionProvider.PrepareSuggestions(tmpFolder, tmpPattern, true);

			Assert.IsNull(this.suggestionProvider.LastSuggestionIndex);
			this.suggestionProvider.GetNextSuggestion();

			string tmpActualSuggestion = this.suggestionProvider.GetPreviousSuggestion();
			Assert.AreEqual(1, this.suggestionProvider.LastSuggestionIndex);
			Assert.AreEqual(tmpFile2, tmpActualSuggestion);
		}

	}
}
